package com.hmall.search.service.impl;


import com.alibaba.fastjson.JSON;
import com.hmall.common.PageDTO.PageDTO;
import com.hmall.common.pojo.Item;
import com.hmall.search.doc.ItemDoc;
import com.hmall.search.doc.RequestParams;
import com.hmall.search.service.ISearchService;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class SearchServiceImpl implements ISearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public void saveOrUpdateEs(String json) {
        try {
            Item item = JSON.parseObject(json, Item.class);
            json = JSON.toJSONString(new ItemDoc(item));

            IndexRequest indexRequest = new IndexRequest("item");
            indexRequest
                    .id(item.getId().toString())
                    .source(json, XContentType.JSON);

            restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteEs(String json) {

        try {
            DeleteRequest deleteRequest = new DeleteRequest("item", json);
            restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Map<String, List<String>> filters(RequestParams requestParams) {
        try {
            SearchRequest request = new SearchRequest("item");
            //查询条件
            buildBasicQuery(requestParams, request);

            request.source().size(0);
            //品牌聚合
            request.source().aggregation(
                    AggregationBuilders
                            .terms("brand")
                            .field("brand")
                            .size(20)
            );
            //分类聚合
            request.source().aggregation(
                    AggregationBuilders
                            .terms("category")
                            .field("category")
                            .size(20)
            );
            //进行查询
            SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);

            List<String> brandList = handleBucket(searchResponse.getAggregations().get("brand"));
            List<String> categoryList = handleBucket(searchResponse.getAggregations().get("category"));

            HashMap<String, List<String>> bucketMap = new HashMap<>();
            bucketMap.put("brand", brandList);
            bucketMap.put("category", categoryList);

            return bucketMap;


        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }

    //解析分类
    public List<String> handleBucket(Terms terms) {
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        List<String> bucketList = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            bucketList.add(bucket.getKeyAsString());
        }
        return bucketList;
    }


    @Override
    public PageDTO<ItemDoc> list(RequestParams requestParams) {

        try {
            SearchRequest request = new SearchRequest("item");
            //查询条件
            buildBasicQuery(requestParams, request);
            //分页
            if (requestParams.getPage() != null && requestParams.getSize() != null) {
                request.source().from((requestParams.getPage() - 1) * requestParams.getSize()).size(requestParams.getSize());
            }

            if (!StringUtils.isEmpty(requestParams.getSortBy()) && !"default".equals(requestParams.getSortBy())) {
                request.source().sort(requestParams.getSortBy(), SortOrder.ASC);
            }

            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

            return handleResponse(response);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //解析数据
    private PageDTO<ItemDoc> handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;

        SearchHit[] hits = searchHits.getHits();
        List<ItemDoc> hotelDocs = new ArrayList<>();
        for (SearchHit hit : hits) {
            ItemDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), ItemDoc.class);
            hotelDocs.add(hotelDoc);
        }
        return new PageDTO(total, hotelDocs);
    }

    //添加查询条件
    private void buildBasicQuery(RequestParams requestParams, SearchRequest request) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //查询所有 或 条件查询
        if (StringUtils.isEmpty(requestParams.getKey())) {
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        } else {
            boolQueryBuilder.must(QueryBuilders.matchQuery("all", requestParams.getKey()));
        }

        //分类
        if (StringUtils.isNotEmpty(requestParams.getCategory())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("category", requestParams.getCategory()));
        }

        //品牌
        if (StringUtils.isNotEmpty(requestParams.getBrand())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("brand", requestParams.getBrand()));
        }

        //价格区间
        if (requestParams.getMinPrice() != null && requestParams.getMaxPrice() != null) {
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("price")
                            .gte(requestParams.getMinPrice() * 100)
                            .lte(requestParams.getMaxPrice() * 100)
            );
        }

        //加权重
        FunctionScoreQueryBuilder functionScoreQuery =
                QueryBuilders.functionScoreQuery(
                        // 原始查询，相关性算分的查询
                        boolQueryBuilder,
                        // function score的数组
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                                // 其中的一个function score 元素
                                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                        // 过滤条件
                                        QueryBuilders.termQuery("isAD", true),
                                        // 算分函数
                                        ScoreFunctionBuilders.weightFactorFunction(10)
                                )
                        });

        request.source().query(functionScoreQuery);

    }
}